package com.ruibang.glass.apigateway.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;


/**
 * @Auther: csz
 * @Date: 2018/8/9 14:57
 * @Description:
 */
@Slf4j
@Component
@Configuration
public class CorsConfig implements GlobalFilter, Ordered {
    private static final String ALL = "*";
    private static final String MAX_AGE = "18000L";

    //添加请求头　
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (!CorsUtils.isCorsRequest(request)) {
                return chain.filter(ctx);
            }
            HttpHeaders requestHeaders = request.getHeaders();
            ServerHttpResponse response = ctx.getResponse();
            HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
            HttpHeaders headers = response.getHeaders();
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
            List<String> valueList = new ArrayList<>();
            valueList.add("Content-Type");
            valueList.add("timestamp");
            valueList.add("sign");
            valueList.add("token");
            valueList.add("X-Device-Id");
            valueList.add("x-requested-with");
            headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, valueList);
            if (requestMethod != null) {
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE,OPTIONS");
            }
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);
            headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
            headers.setAccessControlAllowCredentials(true);
            headers.setAccessControlAllowOrigin(requestHeaders.getOrigin());
            headers.set("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
            headers.setAccessControlMaxAge(18000L);
            headers.set(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);
            headers.set("Access-Control-Allow-Headers", "Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Requested-With,Cache-Control,Content-Type,timestamp,sign,token");
            //解决安全漏洞
            //System.out.println("安全过滤--");
            headers.set("Content-Security-Policy", "frame-ancestors 'self'");
            headers.set("X-Content-Type-Options", "nosniff;");
            headers.set("X-XSS-Protection", "1;mode=block");
            headers.set("Access-Control-Allow-Credentials", "true");
            log.error(ctx.getRequest().getRemoteAddress().toString());

            if (request.getMethod() == HttpMethod.OPTIONS) {
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
            return chain.filter(ctx);
        };
    }

    //将请求头中有多个值的去掉 这是该版本的一个bug
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        // 指定此过滤器位于NettyWriteResponseFilter之后
        // 即待处理完响应体后接着处理响应头
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
    }
}
